package ch.unisi.inf.pfii.teamred.pacman.model;

import java.util.ArrayList;

import ch.unisi.inf.pfii.teamred.pacman.controller.Console;
import ch.unisi.inf.pfii.teamred.pacman.controller.GameListener;

/**
 * This class describes a game of Pacman.
 * 
 * @author luca.vignola@lu.unisi.ch
 * @author mark.pruneri@lu.unisi.ch
 */

public final class Game {

	private final Console console;
	private final HighscoreFileHandler highscoreFileHandler;
	private final Highscore highscore;
	private final ArrayList<GameListener> listeners;

	private Player player;
	private Level level;

	public Game(final String playerName) {
		console = new Console();
		highscoreFileHandler = new HighscoreFileHandler();
		highscore = loadSavedHighscore();
		listeners = new ArrayList<GameListener>();
		level = new Level(1, "Level 1");
		player = new Player(playerName, level.getBoard().getPacman());
	}

	public final Highscore getHighscore() {
		return highscore;
	}

	private final Highscore loadSavedHighscore() {
		highscoreFileHandler.loadHighscoreFromFile();
		return highscoreFileHandler.getHighscore();
	}
	
	public final void saveHighscore() {
		highscoreFileHandler.setHighscore(highscore);
		highscoreFileHandler.saveHighscoreToFile();
	}

	public final void setPlayer(final Player player) {
		this.player = player;
	}

	public final Player getPlayer() {
		return player;
	}

	public final void setLevel(final Level level) {
		this.level = level;
	}

	public final Level getLevel() {
		return level;
	}

	public final String getStatus() {
		return level.getStatus() + "\n" + player.getStatus();
	}
	
	public final void restart() {
		int levelNumber = level.getLevelNumber();
		String levelName = level.getLevelName();
		level = new Level(levelNumber, levelName);
		String playerName = player.getName();
		player = new Player(playerName, level.getBoard().getPacman());
	}

	public final void play() {
		while (true) {
			console.writeLine(getStatus());
			console.writeLine("");
			console.writeLine(level.getBoard().toString());
			console.write("> ");
			Direction playerDirection = console.getDirection();
			if (playerDirection != Direction.NO) {
				player.setPacmanDirection(playerDirection);
			}
			step();
		}
	}

	public final void step() {
		level.getBoard().step();
		updatePlayerStatus();
		checkGame();
	}

	private final void checkGame() {
		if (gameOver()) {
			fireGameOver();
		} else if (gameWon()) {
			fireGameWon();
		}
	}

	private final boolean gameWon() {
		return level.getBoard().noMoreItemsOnBoard();
	}

	private final boolean gameOver() {
		if (player.getLife() == 0) {
			return true;
		} else {
			return false;
		}
	}

	private final void updatePlayerStatus() {
		player.updateStatus();

		if (player.getPacman().isDead()) {
			player.reduceLifeByOne();
			player.getPacman().setAlive();
		}
	}

	public final void setPacmanDirection(Direction playerDirection) {
		player.setPacmanDirection(playerDirection);
	}

	public final void addGameListener(final GameListener listener) {
		listeners.add(listener);
	}

	public final void removeGameListener(final GameListener listener) {
		listeners.remove(listeners);
	}

	private final void fireGameOver() {
		for (final GameListener listener : listeners) {
			listener.gameOver(this);
		}
	}

	private final void fireGameWon() {
		for (final GameListener listener : listeners) {
			listener.gameWon(this);
		}
	}
}
